import type {
  Asyncify,
  GreaterThan,
  Integer,
  IsEqual,
  IsInteger,
  NonNegative,
  UnionToTuple,
} from 'type-fest';
import type { Numeric } from 'type-fest/source/numeric.js';
import type { Bundle } from 'typescript';
// # P = T;
// 一个属性 P 被类型 T expect(分配) 当且仅当满足如下之一条件 (部分)：
// 在 expect 中对普通的右值进行更加严格的检查
// T 不是对象 (object)，联合 (union)，或者交叉 (Intersection) 类型
// T 是对象类型且
// T 存在和 P 同名的属性
// T 存在 string 或者 index signature 如 { [key:string]:string}
// T 不存在属性
// T 是全局的 Object
// T 是一个 union 或者 intersection 类型且 P 是 T 组成 type 的 expect 属性 (这里已经递归了，expect 的判定是个递归算法)
type _extendsFromObj = number extends { toString(): string } ? true : false;
//      ^?
type _extendsFromNull = undefined extends null ? true : false;
//      ^?
// 利用分配法则
type isUnion<T, C = T> = T extends C ? ([C] extends [T] ? false : true) : never;

// via: https://github.com/type-challenges/type-challenges/issues/1140
type IsUnionFinal<T, C extends T = T> = (
  T extends T
    ? C extends T
      ? IsEqual<C, T> extends true
        ? true
        : unknown
      : unknown
    : never
) extends true
  ? false
  : true;

type _ = isUnion<void | undefined>;
//   ^?
type __ = IsUnionFinal<(() => number) | (() => 15)>;
//    ^?

type _1 = undefined | void;

// unknown < void
type _2 = IsEqual<void, void | undefined>;
//    ^?

type isNonNull<T> = T extends { toString(): string } ? 1 : 0;
enum A {
  n,
}
type _s = isNonNull<symbol>;
{
  // The **assignment compatibility** and **subtyping rules** differ only in that
  // 可赋值性和子类型规则只在以下方面不同：
  // - the `any` type is assignable to, but not a subtype of, all types,
  // any 类型是可分配给所有类型的，但是不是所有类型的子类型
  // - the primitive type Number is assignable to, but not a subtype of, all enum types, and
  // 基元类型 Number 可分配给所有枚举类型，但不是所有枚举类型的子类型

  const b: A.n = 0;
  // - an object type without a particular property is assignable to an object type in which that property is optional
  // 没有特定属性的对象类型 可分配给 具有该属性的可选对象类型;
  // 例子
  let c: { a?: 1 } = {};
}
let numbers = {
  *[Symbol.iterator](): Generator<number> {
    yield 1;
    yield 2;
    yield 3;
  },
};
let [one, two, ...rest] = numbers;

{
  // good debug - 忽略错误
  type IsUnionDebug<T, TT = T> = T extends unknown
    ? TT extends T
      ? [T, TT]
      : [T, TT]
    : // `${TT} extends ${T}` :
      // `${TT} doesn't extends ${T}`
      never;

  type Square<T extends number, P = Integer<T>> = 1;
  type TestSquare1 = Square<1>; // 1
  type TestSquare2 = Square<2>; // 4
  type Experiment = IsUnionDebug<1 | 2 | 3>;
  //        ^?

  // TODO: 坐标 to Matrix
  type Tuple = UnionToTuple<Experiment>;
  //     ^?
  type Positive<T extends Numeric> = T extends 0 ? never : NonNegative<T>;
  type test_Positive = Positive<1454>;
  //       ^?
  type Sqrt<T extends number, P = Positive<T>> = T extends infer N extends
    Numeric
    ? N extends P
      ? P
      : never
    : never; /// Make a Mat / use union

  type SortPair<T extends number[]> =
    GreaterThan<T[0], T[1]> extends true ? [T[1], T[0]] : T;
  type _SortPair = SortPair<[2, 1]>;

  type _doSort<T extends any[]> = {
    [k in keyof T extends infer Key
      ? Key extends `${infer NK extends number}`
        ? NK
        : never
      : never]: T[k];
  };
  type _dosort3 = _doSort<Tuple>;
  type Mod = undefined;
  type SqrtTuple = Sqrt<2>;
  //         ^?
}
type D = number extends bigint ? 1 : 0;
//   ^?
type DR = bigint extends number ? 1 : 0;
//   ^?
type whatNumber = `${number}` extends `${infer S}` ? S : never;
//       ^?

type Inf = 1e999; // Resolves to Infinity
type NegativeInf = -1e999; // Resolves to -Infinity
export {};
